<!doctype html>
<html>
    <head>
        <title>Impress Tutorial</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link href="css/impress-demo.css" rel="stylesheet" />
        <link href="css/custom.css" rel="stylesheet" />
        <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.3.1/styles/default.min.css">
        <script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.3.1/highlight.min.js"></script>
        <script>hljs.initHighlightingOnLoad();</script>
    </head>
    <body>

<div id="impress">

<div class="no-support-message" style="display:none;">
    Your browser doesn't support impress.js.  Try Chrome or Safari.
</div>

<div class="step" data-x="0" data-y="0">
    <q>1024节日快乐！</q>
    <p class="normal">
        <image src="img/2.png" height="500"></image>
    </p>
</div>

<div class="step" data-x="2000" data-y="0">
    <q>荐书环节</q>
    <p class="normal">
        <image src="img/1.png" height="500"></image>
    </p>
</div>

<div class="step" data-x="4000" data-y="0">
    <q>另一门脚本语言</q>
    <p class="normal">
        <code class="code">Ruby</code>是一种解释型、面向对象、动态类型的语言。
    </p>
    <pre><code class="ruby codeblock">
    # frozen_string_literal: true

    require "active_record"
    require "benchmark/ips"
    
    TIME    = (ENV["BENCHMARK_TIME"] || 20).to_i
    RECORDS = (ENV["BENCHMARK_RECORDS"] || TIME * 1000).to_i
    
    conn = { adapter: "sqlite3", database: ":memory:" }
    
    ActiveRecord::Base.establish_connection(conn)
    
    class User < ActiveRecord::Base
        connection.create_table :users, force: true do |t|
            t.string :name, :email
            t.timestamps
        end
    
        has_many :exhibits
    end
    </code>
    </pre>
</div>

<div class="step" data-x="6000" data-y="0">
    <q>面向对象</q>
    <p class="normal">
        模糊了方法跟变量的边界，统一成消息的概念，ruby面向对象操作解释成：对象发消息（add_one, multiply_two，value），对象接收到消息给你返回不同的结果。
    </p>
    <pre><code class="ruby codeblock">
    class Operator < Struct.new(:value)
        def add_one
            self.value += 1
            self
        end

        def multiply_two
            self.value *= 2
            self
        end
    end

    op1 = Operator.new(1)
    puts op1.add_one.add_one.multiply_two.value # => 6
    
    op2 = Operator.new(1)
    puts op2.add_one().add_one().multiply_two().value() # => 6
    </code>
    </pre>
</div>

<div class="step" data-x="8000" data-y="0">
    <q>面向对象</q>
    <pre><code class="ruby codeblock">
    小周 = {:姓名 =>小周 "小周", :年龄 => 18, :存款 => 10000000}

    小周.to_json # => NoMethodError: undefined method `to_json'
        
    require "json"

    小周.to_json
    # => "{\"姓名\":\"小周\",\"年龄\":18,\"存款\":10000000}"
    </code></pre>
</div>

<div class="step" data-x="10000" data-y="0">
    <q>一道面试题</q>
    <p class="normal">
        小周去参加一个面试通知，题目是：写一个程序输出数字1到100。但如果数字是3的倍数， 就不输出数字而是输出"Fizz"， 如果是 5 的倍数就输出"Buzz"。 对于那些3和5的公倍数，就输出"FizzBuzz"。
    </p>
</div>

<div class="step" data-x="12000" data-y="0">
    <q>抢答</q>
    <pre><code class="ruby codeblock">
    (1..100).each do |n|
        if (n % 15).zero?
            puts 'FizzBuzz'
        elsif (n % 3).zero?
            puts 'Fizz'
        elsif (n % 5).zero?
            puts 'Buzz'
        else
            puts n.to_s
        end
    end
    </code></pre>
</div>

<div class="step" data-x="14000" data-y="0">
    <q>面试官</q>
    <ol class="normal">
        <li>数字自己实现</li>
        <li>布尔值自己实现</li>
        <li>if语句自己实现</li>
    </ol>
</div>

<div class="step" data-x="16000" data-y="0">
    <q>lambda演算</q>
    <pre><code class="ruby codeblock">
    -> x { x + 1 }.call(1) # => 2

    def add_one(x):
        return x + 1
    
    # 定义一
    inc = -> (x) { x + 1 }
    
    # 定义二
    inc = Proc.new { | x | x + 1 }
     
    # 定义三
    inc = lambda { | x | x + 1 }
     
    # 定义四
    inc = proc { | x | x + 1 }
    
    # 调用一
    inc.call(2) # => 3
    
    # 调用二
    inc[2] # => 3
    </code></pre>
</div>

<div class="step" data-x="18000" data-y="0">
    <q>多参调用</q>
    <pre><code class="ruby codeblock">
    -> (x, y) { x + y }.call(3, 4) # => 7

    # 柯里化: 把接收多参函数变换成接收原来第一个参数的函数，
    # 返回一个接收剩余参数的新函数

    -> x {-> y { x + y }}.call(3).call(4) # => 7

    # 我们想要的效果

    -> x {-> y { x + y }}[3][4] # => 7
    </code></pre>
</div>

<div class="step" data-x="20000" data-y="0">
    <q>实现数字</q>
    <p class="normal">
        “数字”可以用来表示次数，反过来思考次数代表“数字”
    </p>
    <pre><code class="ruby codeblock">
    # 以x为参数调用一次proc函数。one函数表示“一”
    def one(proc, x)
        proc[x]
    end

    # 以x为参数调用一次proc函数，调用结果再次调用proc。two函数表示“二”
    def two(proc, x)
        proc[proc[x]]
    end

    # 以此类推，three函数表示“三”
    def three(proc, x)
        proc[proc[proc[x]]]
    end

    # 不调用proc就是表示“零”
    def zero(proc, x)
        x
    end
    </code></pre>
</div>

<div class="step" data-x="22000" data-y="0">
    <q>实现数字</q>
    <p class="normal">
        使用lambda
    </p>
    <pre><code class="ruby codeblock">
    ZERO = -> p { -> x { x } }
    ONE = -> p { -> x { p[x] } }
    TWO = -> p { -> x { p[p[x]] } }
    THREE = -> p { -> x { p[p[p[x]]] } }

    # 用来打印真实的数字
    def to_integer(proc)
        proc[-> n { n + 1 }][0]
    end

    puts to_integer(ZERO)   # => 0
    puts to_integer(ONE)    # => 1
    puts to_integer(TWO)    # => 2
    puts to_integer(THREE)  # => 3

    # 这种以编码表示数据的技术称为邱奇编码

    # 这种“代码即数据”的概念是不是跟我们认识的“数据即代码”有着和谐的对立？
    </code></pre>
</div>

<div class="step" data-x="24000" data-y="0">
    <q>实现数字</q>
    <p class="normal">
        扩充
    </p>
    <pre><code class="ruby codeblock">
    我们可以扩充到15，100

    FIFTEEN = -> p { -> x { p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[x]]]]]]]]]]]]]]]}}

    HUNDRED = -> p { -> x { p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p
        [p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p
        [p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p
        [p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p
        [p[p[p[p[p[p[p[p[p[p[x]]]]]]]]]]]]]]]]]]]]]]
        ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
        ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }

    puts to_integer(FIFTEEN)  # => 15
    puts to_integer(HUNDRED)  # => 100
    </code></pre>
</div>

<div class="step" data-x="26000" data-y="0">
    <q>实现数字</q>
    <p class="normal">
        修改程序
    </p>
    <pre><code class="ruby codeblock">
    # ONE等数字其实要表示成to_integer(ONE)
    # 因为我们实现的数字还不支持 .. / map / % 等操作，
    # 演示省略后续实现细节
    (ONE..HUNDRED).map do |n|
        if (n % FIFTEEN).zero?
            puts 'FizzBuzz'
        elsif (n % THREE).zero?
            puts 'Fizz'
        elsif (n % FIVE).zero?
            puts 'Buzz'
        else
            n.to_s
        end
    end
    </code></pre>
</div>

<div class="step" data-x="28000" data-y="0">
    <q>实现布尔值</q>
    <p class="normal">
        布尔值就是配合if帮我们做“二选一”
    </p>
    <pre><code class="ruby codeblock">
    def true(x, y)
        x
    end

    def false(x, y)
        y
    end

    success = :true
    puts send(success, "happy", "sad") # => "happy"

    success = :false
    puts send(success, "happy", "sad") # => "sad"

    # send有强大的动态特性，类似其他语言的apply方法，把参数应用到一个方法上
    </code></pre>
</div>

<div class="step" data-x="30000" data-y="0">
    <q>实现布尔值</q>
    <p class="normal">
        使用lambda
    </p>
    <pre><code class="ruby codeblock">
    TRUE = -> x { -> y { x } }
    FALSE = -> x { -> y { y } }

    def to_boolean(proc)
        proc[true][false]
    end

    puts to_boolean(TRUE)   # => true
    puts to_boolean(FALSE)  # => false
    </code></pre>
</div>

<div class="step" data-x="32000" data-y="0">
    <q>实现if语句</q>
    <p class="normal">
        出乎意料的简单
    </p>
    <pre><code class="ruby codeblock">
    # 只要传进来是个布尔值，二选一操作已经实现了
    IF = -> b { -> x { -> y { b[x][y] }}}

    to_boolean也可以修改了

    # 旧的
    def to_boolean(proc)
        proc[true][false]
    end

    # 新的
    def to_boolean(proc)
        IF[proc][true][false]
    end
    </code></pre>
</div>

<div class="step" data-x="34000" data-y="0">
    <q>实现if语句</q>
    <p class="normal">
        化简
    </p>
    <pre><code class="ruby codeblock">
    # 最里面一层是接收一个y的参数，用这个参数调用b[x]
    IF = -> b { -> x { -> y { b[x][y] }}}

    # 化简为 
    # 以此类推，外面一层是接收一个x的参数，用这个参数调用b
    IF = -> b { -> x { b[x] } }

    # 最终可以化简为
    IF = -> b { b }

    # 可以把这一系列化简过程我们可以理解成达成了一种协议：
    # IF接收一个lambda（TRUE/FALSE）并原样返回，这个lambda至少能处理两个参数
    # 这种思路联想到什么：接口？鸭子类型？
    </code></pre>
</div>

<div class="step" data-x="36000" data-y="0">
    <q>实现if语句</q>
    <p class="normal">
        修改我们的程序
    </p>
    <pre><code class="ruby codeblock">
    (ONE..HUNDRED).map do |n|
        IF[(n % FIFTEEN).zero?][
            'FizzBuzz'
        ][IF[(n % THREE).zero?][
            'Fizz'
        ][IF[(n % FIVE).zero?][
            'Buzz'
        ][
            n.to_s
        ]]]
    end
    </code></pre>
</div>

<div class="step" data-x="38000" data-y="0">
    <q>故事结束了，我们可以做的还有更多</q>
    <ol class="normal">
        <li>实现零值判断</li>
        <li>实现加法/减法/乘法/乘方</li>
        <li>实现数值大小比较</li>
        <li>实现取模</li>
        <li>实现列表</li>
        <li>实现MAP</li>
        <li>实现字符串</li>
        <li>...</li>
    </ol>
</div>

<div class="step" data-x="40000" data-y="0">
    <q>浪漫的终极梦想</q>
    <p class="normal">
        实现lambda...你拥有了整个世界！
    </p>
    <image src="img/3.png" height="500"></image>
</div>

<div class="step" data-x="42000" data-y="0">
    <q>谢谢！周末愉快！</q>
</div>

</div>
    <script type="text/javascript" src="js/impress.js"></script>
    <script>impress();</script>
    </body>
</html>

